import axios from './index';
import qs from 'qs';

import type { AxiosResponse } from 'axios';

export enum ContentType { Json = 1, FormUrlencoded = 2, FormData = 3 }

export class HttpConfig {
    constructor() {
        this.prefix = 'input';
        this.params = {};
        this.contentType = ContentType.Json;
    }

    public url!: string;
    public prefix?: string;
    public params?: any;
    public contentType?: ContentType;
}

export class HttpApi {
    public async httpGet(config: HttpConfig): Promise<any> {
        return this.httpSend('get', config);
    }

    public async httpPost(config: HttpConfig): Promise<any> {
        return this.httpSend('post', config);
    }

    public async httpPut(config: HttpConfig): Promise<any> {
        return this.httpSend('put', config);
    }

    public async httpDelete(config: HttpConfig): Promise<any> {
        return this.httpSend('delete', config);
    }

    private async httpSend(method: string, config: HttpConfig): Promise<any> {
        const config2: HttpConfig = new HttpConfig;
        config.prefix = config.prefix || config2.prefix;
        config.params = config.params || config2.params;
        config.contentType = config.contentType || config2.contentType;
        let send: Promise<AxiosResponse<any, any>>;
        switch (method) {
            case 'get':
            default:
                send = axios.get(config.url, { params: config.params });
                break;
            case 'post':
                send = axios.post(config.url, this.getData(config.prefix!, config.params, config.contentType));
                break;
            case 'put':
                send = axios.put(config.url, this.getData(config.prefix!, config.params, config.contentType));
                break;
            case 'delete':
                send = axios.delete(config.url, { params: config.params });
                break;
        }

        let reuslt: Promise<any>;
        try {
            const res: AxiosResponse<any, any> = await send;
            reuslt = Promise.resolve(res.data.data);
        } catch (error) {
            reuslt = Promise.reject(error);
        } finally {
        }

        return reuslt;
    }

    private getData(prefix: string, params: any, contentType: ContentType = ContentType.Json): any {
        let data: any;
        switch (contentType) {
            case ContentType.Json:
                data = params;
                break;
            case ContentType.FormUrlencoded:
                data = qs.stringify(params);
                break;
            case ContentType.FormData:
                data = this.parseJson2Form(prefix, params);
                break;
        }
        return data;
    }

    private parseJson2Form(prefix: string, JsonObject: any): any {
        const realPrefix: string = !prefix ? 'input' : prefix;
        const resObj: FormData = new FormData;
        const gettype: () => string = Object.prototype.toString;
        for (const key in JsonObject) {
            const tmpVal = JsonObject[key];
            const typeStr: string = gettype.call(tmpVal);
            if (!tmpVal) {
                continue;
            }
            if (this.isSimpleType(typeStr)) {
                resObj.append(realPrefix + '.' + key, tmpVal + '');
            } else if (typeStr == '[object File]') {
                resObj.append(realPrefix + '.' + key, tmpVal);
            } else if (typeStr == '[object Object]') {
                this._recursive_parseJson2Form_(resObj, realPrefix + '.' + key, tmpVal);
            } else if (typeStr == '[object Array]') {
                if (tmpVal.length <= 0) {
                    continue;
                }

                let isSimpleArray: boolean = false;
                for (const arrIndex in tmpVal) {
                    const childItem = tmpVal[arrIndex];
                    const childTypeStr: string = gettype.call(childItem);
                    if (this.isSimpleType(childTypeStr)) {
                        isSimpleArray = true;
                    }
                }
                let nowIndex: number = 0;
                if (isSimpleArray) {
                    for (const arrIndex in tmpVal) {
                        const childItem = tmpVal[arrIndex];
                        resObj.append(realPrefix + '.' + key + '[' + nowIndex + ']', childItem);
                        nowIndex++;
                    }
                } else {
                    for (const arrIndex in tmpVal) {
                        const childItem = tmpVal[arrIndex];
                        this._recursive_parseJson2Form_(resObj, realPrefix + '.' + key + '[' + nowIndex + ']', childItem);
                        nowIndex++;
                    }
                }
            }
        }

        return resObj;
    }

    private isSimpleType(typeStr: string): boolean {
        return typeStr == '[object String]'
            || typeStr == '[object Number]'
            || typeStr == '[object Boolean]'
            || typeStr == '[object Null]'
            || typeStr == '[object Undefined]'
    }

    private _recursive_parseJson2Form_(resObj: any, parentKey: any, JsonObject: any): any {
        const gettype: () => string = Object.prototype.toString;
        for (const key in JsonObject) {
            const tmpVal = JsonObject[key];
            const typeStr: string = gettype.call(tmpVal);
            if (!tmpVal) {
                continue;
            }
            if (this.isSimpleType(typeStr)) {
                resObj.append(parentKey + '.' + key, tmpVal + '');
            } else if (typeStr == '[object File]') {
                resObj.append(parentKey + '.' + key, tmpVal);
            } else if (typeStr == '[object Object]') {
                this._recursive_parseJson2Form_(resObj, parentKey + '.' + key, tmpVal);
            } else if (typeStr == '[object Array]') {
                if (tmpVal.length <= 0) {
                    continue;
                }

                let isSimpleArray: boolean = false;
                for (const arrIndex in tmpVal) {
                    const childItem = tmpVal[arrIndex];
                    const childTypeStr: string = gettype.call(childItem);

                    if (this.isSimpleType(childTypeStr)) {
                        isSimpleArray = true;
                    }
                }
                let nowIndex: number = 0;
                if (isSimpleArray) {
                    for (const arrIndex in tmpVal) {
                        const childItem = tmpVal[arrIndex];
                        resObj.append(parentKey + '.' + key + '[' + nowIndex + ']', childItem);
                        nowIndex++;
                    }
                } else {
                    for (const arrIndex in tmpVal) {
                        const childItem = tmpVal[arrIndex];
                        this._recursive_parseJson2Form_(resObj, parentKey + '.' + key + '[' + nowIndex + ']', childItem);
                        nowIndex++;
                    }
                }
            }
        }
    }
}

export const httpApi = new HttpApi;